import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { DiaryTemplate, TemplateEntry, TemplateSection } from '../types/templates';
import { PREDEFINED_TEMPLATES } from '../data/predefinedTemplates';

export interface DiaryEntry {
  id: string;
  title: string;
  content: string;
  date: string;
  mood: string;
  tags: string[];
  createdAt: string;
  updatedAt: string;
  templateId?: string;
  templateSections?: { [sectionId: string]: string };
}

export interface DiaryStore {
  entries: DiaryEntry[];
  searchQuery: string;
  selectedMood: string;
  selectedTags: string[];
  dateRange: { start: string; end: string } | null;
  
  // Template state
  templates: DiaryTemplate[];
  customTemplates: DiaryTemplate[];
  selectedTemplate: DiaryTemplate | null;
  
  // Actions
  addEntry: (entry: Omit<DiaryEntry, 'id' | 'createdAt' | 'updatedAt'>) => void;
  updateEntry: (id: string, updates: Partial<DiaryEntry>) => void;
  deleteEntry: (id: string) => void;
  setSearchQuery: (query: string) => void;
  setSelectedMood: (mood: string) => void;
  setSelectedTags: (tags: string[]) => void;
  toggleTag: (tag: string) => void;
  setDateRange: (range: { start: string; end: string } | null) => void;
  
  // Template actions
  setSelectedTemplate: (template: DiaryTemplate | null) => void;
  addCustomTemplate: (template: Omit<DiaryTemplate, 'id' | 'isCustom' | 'usageCount'>) => void;
  updateTemplate: (id: string, updates: Partial<DiaryTemplate>) => void;
  deleteTemplate: (id: string) => void;
  toggleTemplateFavorite: (id: string) => void;
  incrementTemplateUsage: (id: string) => void;
  
  // Computed
  getFilteredEntries: () => DiaryEntry[];
  getRecentEntries: (limit?: number) => DiaryEntry[];
  getEntryById: (id: string) => DiaryEntry | undefined;
  getAllTags: () => string[];
  getPopularTags: (limit?: number) => { tag: string; count: number }[];
  getStats: () => {
    totalEntries: number;
    entriesThisMonth: number;
    longestStreak: number;
  };
  
  // Chart data functions
  getEntriesOverTime: (days?: number) => { date: string; entries: number }[];
  getMoodDistribution: () => { mood: string; count: number; percentage: number }[];
  getTemplateUsageStats: () => { template: string; count: number; percentage: number }[];
  getWritingStreakData: () => { date: string; hasEntry: number; streak: number }[];
  
  // Template computed
  getAllTemplates: () => DiaryTemplate[];
  getTemplateById: (id: string) => DiaryTemplate | undefined;
  getTemplatesByCategory: (category: string) => DiaryTemplate[];
  getFavoriteTemplates: () => DiaryTemplate[];
  getMostUsedTemplates: (limit?: number) => DiaryTemplate[];
}

const generateId = () => Math.random().toString(36).substr(2, 9);

const getCurrentDate = () => new Date().toISOString();

const formatDate = (date: string) => {
  return new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
};

export const useDiaryStore = create<DiaryStore>()(persist(
  (set, get) => ({
    entries: [],
    searchQuery: '',
    selectedMood: '',
    selectedTags: [],
    dateRange: null,
    
    // Template state
    templates: PREDEFINED_TEMPLATES,
    customTemplates: [],
    selectedTemplate: null,
    
    addEntry: (entry) => {
      const newEntry: DiaryEntry = {
        ...entry,
        id: generateId(),
        createdAt: getCurrentDate(),
        updatedAt: getCurrentDate(),
      };
      set((state) => ({
        entries: [newEntry, ...state.entries]
      }));
    },
    
    updateEntry: (id, updates) => {
      set((state) => ({
        entries: state.entries.map((entry) =>
          entry.id === id
            ? { ...entry, ...updates, updatedAt: getCurrentDate() }
            : entry
        )
      }));
    },
    
    deleteEntry: (id) => {
      set((state) => ({
        entries: state.entries.filter((entry) => entry.id !== id)
      }));
    },
    
    setSearchQuery: (query) => set({ searchQuery: query }),
    setSelectedMood: (mood) => set({ selectedMood: mood }),
    setSelectedTags: (tags) => set({ selectedTags: tags }),
    toggleTag: (tag) => {
      const { selectedTags } = get();
      const newTags = selectedTags.includes(tag)
        ? selectedTags.filter(t => t !== tag)
        : [...selectedTags, tag];
      set({ selectedTags: newTags });
    },
    setDateRange: (range) => set({ dateRange: range }),
    
    // Template actions
    setSelectedTemplate: (template) => set({ selectedTemplate: template }),
    
    addCustomTemplate: (template) => {
      const newTemplate: DiaryTemplate = {
        ...template,
        id: generateId(),
        isCustom: true,
        usageCount: 0,
      };
      set((state) => ({
        customTemplates: [...state.customTemplates, newTemplate]
      }));
    },
    
    updateTemplate: (id, updates) => {
      set((state) => ({
        customTemplates: state.customTemplates.map((template) =>
          template.id === id ? { ...template, ...updates } : template
        )
      }));
    },
    
    deleteTemplate: (id) => {
      set((state) => ({
        customTemplates: state.customTemplates.filter((template) => template.id !== id)
      }));
    },
    
    toggleTemplateFavorite: (id) => {
      set((state) => {
        const updatedTemplates = state.templates.map((template) =>
          template.id === id ? { ...template, isFavorite: !template.isFavorite } : template
        );
        const updatedCustomTemplates = state.customTemplates.map((template) =>
          template.id === id ? { ...template, isFavorite: !template.isFavorite } : template
        );
        return {
          templates: updatedTemplates,
          customTemplates: updatedCustomTemplates
        };
      });
    },
    
    incrementTemplateUsage: (id) => {
      set((state) => {
        const updatedTemplates = state.templates.map((template) =>
          template.id === id ? { ...template, usageCount: template.usageCount + 1 } : template
        );
        const updatedCustomTemplates = state.customTemplates.map((template) =>
          template.id === id ? { ...template, usageCount: template.usageCount + 1 } : template
        );
        return {
          templates: updatedTemplates,
          customTemplates: updatedCustomTemplates
        };
      });
    },
    
    getFilteredEntries: () => {
      const { entries, searchQuery, selectedMood, selectedTags, dateRange } = get();
      
      return entries.filter((entry) => {
        const matchesSearch = !searchQuery || 
          entry.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
          entry.content.toLowerCase().includes(searchQuery.toLowerCase()) ||
          entry.tags.some(tag => tag.toLowerCase().includes(searchQuery.toLowerCase()));
        
        const matchesMood = !selectedMood || entry.mood === selectedMood;
        
        const matchesTags = selectedTags.length === 0 || 
          selectedTags.every(tag => entry.tags.includes(tag));
        
        const matchesDateRange = !dateRange || (
          new Date(entry.date) >= new Date(dateRange.start) &&
          new Date(entry.date) <= new Date(dateRange.end)
        );
        
        return matchesSearch && matchesMood && matchesTags && matchesDateRange;
      });
    },
    
    getRecentEntries: (limit = 5) => {
      const { entries } = get();
      return entries.slice(0, limit);
    },
    
    getEntryById: (id) => {
      const { entries } = get();
      return entries.find((entry) => entry.id === id);
    },
    
    getAllTags: () => {
      const { entries } = get();
      const allTags = entries.flatMap(entry => entry.tags || []);
      return [...new Set(allTags)].sort();
    },
    
    getPopularTags: (limit = 10) => {
      const { entries } = get();
      const tagCounts: Record<string, number> = {};
      
      entries.forEach(entry => {
        (entry.tags || []).forEach(tag => {
          tagCounts[tag] = (tagCounts[tag] || 0) + 1;
        });
      });
      
      return Object.entries(tagCounts)
        .map(([tag, count]) => ({ tag, count }))
        .sort((a, b) => b.count - a.count)
        .slice(0, limit);
    },
    
    getStats: () => {
    const { entries } = get();
    const now = new Date();
    const currentMonth = now.getMonth();
    const currentYear = now.getFullYear();
    
    const entriesThisMonth = entries.filter((entry) => {
      const entryDate = new Date(entry.date);
      return entryDate.getMonth() === currentMonth && entryDate.getFullYear() === currentYear;
    }).length;
    
    // Calculate longest streak (simplified)
    let longestStreak = 0;
    let currentStreak = 0;
    const sortedEntries = [...entries].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
    
    for (let i = 0; i < sortedEntries.length; i++) {
      if (i === 0) {
        currentStreak = 1;
      } else {
        const prevDate = new Date(sortedEntries[i - 1].date);
        const currentDate = new Date(sortedEntries[i].date);
        const diffTime = Math.abs(prevDate.getTime() - currentDate.getTime());
        const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
        
        if (diffDays === 1) {
          currentStreak++;
        } else {
          longestStreak = Math.max(longestStreak, currentStreak);
          currentStreak = 1;
        }
      }
    }
    longestStreak = Math.max(longestStreak, currentStreak);
    
    return {
      totalEntries: entries.length,
      entriesThisMonth,
      longestStreak
    };
  },
  
  // Chart data functions
  getEntriesOverTime: (days = 30) => {
    const { entries } = get();
    const now = new Date();
    const startDate = new Date(now.getTime() - (days * 24 * 60 * 60 * 1000));
    
    const dateMap: Record<string, number> = {};
    
    // Initialize all dates with 0
    for (let i = 0; i < days; i++) {
      const date = new Date(startDate.getTime() + (i * 24 * 60 * 60 * 1000));
      const dateStr = date.toISOString().split('T')[0];
      dateMap[dateStr] = 0;
    }
    
    // Count entries per date
    entries.forEach(entry => {
      const entryDate = new Date(entry.date);
      if (entryDate >= startDate) {
        const dateStr = entryDate.toISOString().split('T')[0];
        if (dateMap.hasOwnProperty(dateStr)) {
          dateMap[dateStr]++;
        }
      }
    });
    
    return Object.entries(dateMap)
      .map(([date, count]) => ({
        date: new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
        entries: count
      }))
      .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
  },
  
  getMoodDistribution: () => {
    const { entries } = get();
    const moodCounts: Record<string, number> = {};
    
    entries.forEach(entry => {
      if (entry.mood) {
        moodCounts[entry.mood] = (moodCounts[entry.mood] || 0) + 1;
      }
    });
    
    return Object.entries(moodCounts)
      .map(([mood, count]) => ({ mood, count, percentage: Math.round((count / entries.length) * 100) }))
      .sort((a, b) => b.count - a.count);
  },
  
  getTemplateUsageStats: () => {
    const { entries, getAllTemplates } = get();
    const templates = getAllTemplates();
    const templateCounts: Record<string, number> = {};
    
    entries.forEach(entry => {
      if (entry.templateId) {
        const template = templates.find(t => t.id === entry.templateId);
        const templateName = template?.name || 'Unknown Template';
        templateCounts[templateName] = (templateCounts[templateName] || 0) + 1;
      }
    });
    
    const totalTemplateEntries = Object.values(templateCounts).reduce((sum, count) => sum + count, 0);
    
    return Object.entries(templateCounts)
      .map(([template, count]) => ({
        template,
        count,
        percentage: totalTemplateEntries > 0 ? Math.round((count / totalTemplateEntries) * 100) : 0
      }))
      .sort((a, b) => b.count - a.count);
  },
  
  getWritingStreakData: () => {
    const { entries } = get();
    const now = new Date();
    const last30Days = [];
    
    for (let i = 29; i >= 0; i--) {
      const date = new Date(now.getTime() - (i * 24 * 60 * 60 * 1000));
      const dateStr = date.toISOString().split('T')[0];
      const hasEntry = entries.some(entry => entry.date.split('T')[0] === dateStr);
      
      last30Days.push({
        date: date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
        hasEntry: hasEntry ? 1 : 0,
        streak: 0 // Will be calculated below
      });
    }
    
    // Calculate streak values
    let currentStreak = 0;
    for (let i = last30Days.length - 1; i >= 0; i--) {
      if (last30Days[i].hasEntry) {
        currentStreak++;
        last30Days[i].streak = currentStreak;
      } else {
        currentStreak = 0;
        last30Days[i].streak = 0;
      }
    }
    
    return last30Days;
  },
    
    // Template computed methods
    getAllTemplates: () => {
      const { templates, customTemplates } = get();
      return [...templates, ...customTemplates];
    },
    
    getTemplateById: (id) => {
      const { templates, customTemplates } = get();
      return [...templates, ...customTemplates].find((template) => template.id === id);
    },
    
    getTemplatesByCategory: (category) => {
      const { templates, customTemplates } = get();
      return [...templates, ...customTemplates].filter((template) => template.category === category);
    },
    
    getFavoriteTemplates: () => {
      const { templates, customTemplates } = get();
      return [...templates, ...customTemplates].filter((template) => template.isFavorite);
    },
    
    getMostUsedTemplates: (limit = 5) => {
      const { templates, customTemplates } = get();
      return [...templates, ...customTemplates]
        .sort((a, b) => b.usageCount - a.usageCount)
        .slice(0, limit);
    }
  }),
  {
    name: 'diary-storage',
  }
));